﻿//AcademicPlanner - course registration planning web app.
//Copyright (C) 2009  Boubacar Diallo

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AcademicPlanner.Framework.Helpers;
using AcademicPlanner.Framework.Libraries.Mvc;
using AcademicPlanner.Framework.Libraries.Validation;
using AcademicPlanner.Domain;
using AcademicPlanner.Domain.Models;
using AcademicPlanner.Presentation.Views.Accounts;

namespace AcademicPlanner.Presentation.Controllers
{
	/// <summary>
	/// AccountsController is the Mvc controller for requests
	/// under /Accounts/* in the AcademicPlanner application
	/// web site.
	/// </summary>
	/// <since>1.0</since>
	public class AccountsController : Controller
	{
		/// <summary>
		/// Handles the web request to update a user's account information;
		/// namely his password. This method makes sure the the password
		/// submitted is identical to the second password submitted for
		/// confirmation before forwarding the request to the domain layer.
		/// </summary>
		/// <param name="pId">The identefier of the user's account in the domain layer.</param>
		/// <returns>Instructions to the browser in json format about the result of the action.</returns>
		/// <seealso cref="T:AcademicPlanner.Presentation.JsonResultData"/>
		/// <seealso cref="T:AcademicPlanner.Presentation.FormSubmission"/>
		/// <seealso cref="P:Application"/>
		/// <seealso cref="P:AcademicPlanner.Presentation.AcademicPlannerWebApp.DomainMaster"/>
		/// <seealso cref="P:AcademicPlanner.Domain.DomainMaster.Membership"/>
		/// <seealso cref="M:AcademicPlanner.Domain.Components.MembershipMngr.SaveAccount"/>
		/// <since>1.0</since>
		[AcceptVerbs(HttpVerbs.Post)]
		[AjaxOnly]
		public JsonResult Save(int pId)
		{
			JsonResultData vResult = new JsonResultData();

			Post.NamesPrefix = "";
			var vPassword = Post.GetAsString("Password", "User");
			var vConfirmPassword = Post.GetAsString("RepeatedPassword", "User");

			try
			{
				if (!StringValidator.IsIdenticalTo(vConfirmPassword, vPassword))
				{
					vResult.errors = Form.SummarizeError(string.Format(Tr("{0} must be the same as {1}."),
																		Labels.Get("RepeatedPassword", "User"),
																		Labels.Get("Password", "User")));
				}
				else
				{
					Application.DomainMaster.Membership.SaveAccount(pId, vPassword);

					SessionHelper.AddSuccessStatusMessage(string.Format(Tr("Congratulations! Your account " +
						"password was successfully updated.")));
					vResult.reload = true;
				}
			}
			catch (InvalidModelPropertiesException vIx)
			{
				vResult.errors = Form.SummarizeErrors(vIx.Errors);
			}
			catch (NotCriticalDomainException vNcx)
			{
				SessionHelper.AddInfoStatusMessage(Tr(vNcx.Message));
				vResult.reload = true;
			}

			return Json(vResult);
		}

		/// <summary>
		/// Processes a web request to reset the user's account.
		/// </summary>
		/// <remarks>
		/// This method makes sure the the password submitted is identical 
		/// to the second password submitted for confirmation before 
		/// forwarding the request to the domain layer.
		/// </remarks>
		/// <param name="pId">
		/// The identifier of the person trying to reset his account in the domain layer.
		/// </param>
		/// <returns>Instructions to the browser in json format about the result of the action.</returns>
		/// <seealso cref="T:AcademicPlanner.Presentation.JsonResultData"/>
		/// <seealso cref="T:AcademicPlanner.Presentation.FormSubmission"/>
		/// <seealso cref="P:Application"/>
		/// <seealso cref="P:AcademicPlanner.Presentation.AcademicPlannerWebApp.DomainMaster"/>
		/// <seealso cref="P:AcademicPlanner.Domain.DomainMaster.Membership"/>
		/// <seealso cref="M:AcademicPlanner.Domain.Components.MembershipMngr.ResetPersonAccount"/>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.SessionHelper.AddSuccessStatusMessage"/>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.SessionHelper.AddInfoStatusMessage"/>
		/// <since>1.0</since>
		[AcceptVerbs(HttpVerbs.Post)]
		[AjaxOnly]
		public JsonResult Reset(int pId)
		{
			JsonResultData vResult = new JsonResultData();

			Post.NamesPrefix = "";
			var vAcctIndex = Post.GetAsInteger("accountIndex");
			var vPassword = Post.GetAsString("Password", "User", vAcctIndex);
			var vConfirmPassword = Post.GetAsString("RepeatedPassword", "User", vAcctIndex);

			if (vAcctIndex < 0)
			{
				vResult.errors = Form.SummarizeError(Tr("You must select an account to recover."));
			}
			else if (!StringValidator.IsIdenticalTo(vConfirmPassword, vPassword))
			{
				vResult.errors = Form.SummarizeError(string.Format(Tr("{0} must be the same as {1}."),
																	Labels.Get("RepeatedPassword", "User"),
																	Labels.Get("Password", "User")));
			}
			else
			{
				var vToken = (string)SessionHelper.Get("Presentation.AccountsController.RecoverToken") ?? "";
				var vEmail = (string)SessionHelper.Get("Presentation.AccountsController.RecoverEmail") ?? "";
				try
				{
					Application.DomainMaster.Membership
						.ResetPersonAccount(vToken, pId, vEmail, vAcctIndex, vPassword);

					SessionHelper.AddSuccessStatusMessage(string.Format(Tr("Congratulations! Your account " +
						"password was successfully reset. You may now login with the new password.")));
					vResult.redirect = Url.Action("Default", "Site");
					vResult.evaluate = string.Format("\nCookie.remove('{0}', {{path: '/'}});",
											(string)ConfigHelper.GetPresentationSectionValue("loginSettings", "passwordCookieName"));
				}
				catch (InvalidModelPropertiesException vIx)
				{
					vResult.errors = Form.SummarizeErrors(vIx.Errors);
				}
				catch (NotCriticalDomainException vNcx)
				{
					SessionHelper.AddInfoStatusMessage(Tr(vNcx.Message));
					vResult.reload = true;
				}
			}

			return Json(vResult);
		}

		/// <summary>
		/// Displays a web page to help the user recover his account.
		/// </summary>
		/// <remarks>
		/// This method retrieves the list of usernames of all accounts possessed
		/// by the person with the given identifier and email address in the system.
		/// </remarks>
		/// <param name="pFromEmail">The email address of the person to help recover his account.</param>
		/// <param name="pToken">The verification token that was sent to the person's email address.</param>
		/// <param name="pPersonId">The identifier of the person in the domain layer.</param>
		/// <returns>A Accounts/Recover view in a InNoSection master page.</returns>
		/// <seealso cref="P:Application"/>
		/// <seealso cref="P:AcademicPlanner.Presentation.AcademicPlannerWebApp.DomainMaster"/>
		/// <seealso cref="P:AcademicPlanner.Domain.DomainMaster.Membership"/>
		/// <seealso cref="M:AcademicPlanner.Domain.Components.MembershipMngr.GetAccountUserNamesToReset"/>
		/// <since>1.0</since>
		[AcceptVerbs(HttpVerbs.Get)]
		public ViewResult Recover(string pFromEmail, string pToken, int pPersonId)
		{
			var vViewModel = new RecoverAccountModel();

			SessionHelper.Reset("Presentation.AccountsController.RecoverToken", pToken);
			SessionHelper.Reset("Presentation.AccountsController.RecoverEmail", pFromEmail);
			vViewModel.Email = pFromEmail;
			vViewModel.PersonId = pPersonId;
			vViewModel.AccountUserNames = Application.DomainMaster.Membership
														.GetAccountUserNamesToReset(pToken, pPersonId, pFromEmail);

			return View("Recover", "InNoSection", vViewModel);
		}
	}
}
